package com.bwie.spike.service.impl;

import com.alibaba.fastjson.JSON;

import com.alibaba.fastjson.TypeReference;
import com.bwie.common.utils.R;
import com.bwie.spike.entity.GoodsEntity;
import com.bwie.spike.entity.MiaoshaOrderEntity;
import com.bwie.spike.service.GoodsService;
import com.bwie.spike.service.MiaoshaOrderService;
import com.bwie.spike.service.UserService;
import org.apache.commons.lang.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bwie.common.utils.PageUtils;
import com.bwie.common.utils.Query;

import com.bwie.spike.dao.OrderInfoDao;
import com.bwie.spike.entity.OrderInfoEntity;
import com.bwie.spike.service.OrderInfoService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import static com.bwie.common.utils.GetOrderNumber.getOrderIdByTime;


@Service("orderInfoService")
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoDao, OrderInfoEntity> implements OrderInfoService {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private OrderInfoDao orderInfoDao;

    @Autowired
    private UserService userService;

    @Autowired
    private GoodsService goodsService;

    @Autowired
    private MiaoshaOrderService miaoshaOrderService;

    @Autowired
    private RedissonClient redissonClient;

    ThreadPoolExecutor executor = new ThreadPoolExecutor(8, 20, 30, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000));


    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderInfoEntity> page = this.page(
                new Query<OrderInfoEntity>().getPage(params),
                new QueryWrapper<OrderInfoEntity>()
        );
        return new PageUtils(page);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R GrabSingle(String user, String good) {
        boolean flag=false;
        //判断用户是否下单过
        //List<OrderInfoEntity> user_id = orderInfoDao.selectList(new QueryWrapper<OrderInfoEntity>().eq("user_id", user).eq("goods_id",good));
        List<Object> order = stringRedisTemplate.opsForHash().values("order");
        List<OrderInfoEntity> orderInfoEntities = JSON.parseObject(order.toString(), new TypeReference<List<OrderInfoEntity>>() {
        });
        for (OrderInfoEntity e : orderInfoEntities) {
            if (e.getUserId().equals(Long.parseLong(user)) && e.getGoodsId().equals(Long.parseLong(good))){
                flag=true;
            }
        }
        if (flag==false){
            stringRedisTemplate.opsForValue().set(user+"user", "1");
            RLock lock = redissonClient.getLock("lock");
            //加锁抢单
            try {
                lock.lock();
                GoodsEntity e = goodsService.getById(good);
                if (e.getGoodsStock()==-1 || e.getGoodsStock()>=1){
                    String s = stringRedisTemplate.opsForValue().get(user + "user");
                    if (StringUtils.isNotBlank(s)){
                        //进行下单操作
                        OrderInfoEntity orderInfo = new OrderInfoEntity();
                        String orderIdByTime = getOrderIdByTime();
                        orderInfo.setId(Long.parseLong(orderIdByTime));
                        orderInfo.setGoodsName(e.getGoodsName());
                        orderInfo.setUserId(Long.parseLong(user));
                        orderInfo.setGoodsId(e.getId());
                        orderInfo.setGoodsCount(1);
                        orderInfo.setGoodsPrice(e.getGoodsPrice());
                        orderInfo.setCreateDate(new Date());
                        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                            rabbitTemplate.convertAndSend("07a", JSON.toJSONString(orderInfo));
                        }, executor);
                        try {
                            CompletableFuture.allOf(future).get();
                        } catch (InterruptedException interruptedException) {
                            interruptedException.printStackTrace();
                        } catch (ExecutionException executionException) {
                            executionException.printStackTrace();
                        }
                        //订单记录表
                        MiaoshaOrderEntity miaoshaOrder = new MiaoshaOrderEntity();
                        miaoshaOrder.setUserId(Long.parseLong(user));
                        miaoshaOrder.setOrderId(Long.parseLong(orderInfo.getId()+""));
                        miaoshaOrder.setGoodsId(Long.parseLong(e.getId()+""));
                        boolean save = miaoshaOrderService.save(miaoshaOrder);
                        //创建订单成功后再进行减库存操作
                        if (save){
                            e.setGoodsStock(e.getGoodsStock()-1);
                            goodsService.updateById(e);
                            //System.out.println(4 / 0);
                            return R.ok("成功啦");
                        }
                    }

                }
                return R.error("库存不足或秒杀失败");
            } catch (ArithmeticException e){
                //当我们使用catch对某一个业务进行包裹时 我们的事物会失效 即使你指定了回滚类型为所有异常 这里我们采用手动提交事物的方式让事物生效
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                e.printStackTrace();
                return R.error("秒杀失败");

            }finally {
                if(lock.isLocked()){
                    if(lock.isHeldByCurrentThread()){
                        lock.unlock();
                    }
                }
            }
        }
        return R.error("已经抢单过了");

    }



}

